import { Vector3, Raycaster, BoxGeometry, Mesh, MeshBasicMaterial } from "three";
import { App } from "../../application";
import Events from "../../application/constants/Events";
import Polyline from "../models/Polyline";
import EditRoute from "./editRoute/EditRoute";
import Const from "../../application/constants/Const";
import { Point } from "../../renderExtension/types/Point";

export default class EditFlight {
    private editRoute: EditRoute;
    private app: App;
    private flightParam: { pointArray: Array<Point>, lineWidth: number, lineColor: string, blockedColor: string, initHeight: number, editMode: 'sameHeight' | 'addHeight', grounds, minDistanceFromGround: number, maxDistanceFromGround: number, sidewipeDistance: number, keybordDistance?: number, narrowCountFactor?: number, narrorColor?: string, stencilRef?: number};
    private verticalParam: { lineWidth: number, lineColor: string };
    private flightRange: { circelCenter: Point, circleRadius: number };
    private isFirstClick: boolean = true;
    private isStartOperator: boolean = false; //是否开启编辑航线
    private leftClickCallback;
    private rightClickCallback;
    private editWaypoinCallback;
    private polyline: Polyline;
    private isDisposed: boolean = false;
    private isDragStatus: boolean = false; //是否有航点处于可拖拽的状态
    public static instance: EditFlight;

    public constructor(flightParam: { pointArray: Array<Point>, lineWidth: number, lineColor: string, blockedColor: string, initHeight: number, editMode: 'sameHeight' | 'addHeight', grounds, minDistanceFromGround: number, maxDistanceFromGround: number, sidewipeDistance: number, keybordDistance?: number, narrowCountFactor?: number, narrorColor?: string, stencilRef?: number},
        verticalParam: { lineWidth: number, lineColor: string }, flightRange?: { circelCenter: Point, circleRadius: number }) {

        EditFlight.instance = this;

        this.flightParam = flightParam;
        if (!this.flightParam.minDistanceFromGround) {
            this.flightParam.minDistanceFromGround = 20; //离地安全距离默认是20
        }
        if (!this.flightParam.maxDistanceFromGround) {
            this.flightParam.maxDistanceFromGround = 600; //离地最大距离默认是600
        }
        this.verticalParam = verticalParam || { lineWidth: 5, lineColor: '#FFFFFF' };
        this.flightRange = flightRange;
        this.app = App.getInstance();

        let lineData = {
            pointArray: this.flightParam.pointArray,  //多边形的顶点数组
            color: this.flightParam.lineColor || '#00FA9A',
            blockedColor: this.flightParam.blockedColor || '#000000',
            lineWidth: this.flightParam.lineWidth || 5,  //线的宽度
            isCricleLine: false, //绘制的线是否是环形的
            depthTest: true,
            stencilRef: this.flightParam.stencilRef
        };

        this.polyline = new Polyline(lineData);
        this.app.add(this.polyline);

        this.editRoute = new EditRoute({ realLine: this.polyline, grounds: this.flightParam.grounds, minDistanceFromGround: this.flightParam.minDistanceFromGround, maxDistanceFromGround: this.flightParam.maxDistanceFromGround, sidewipeDistance: this.flightParam.sidewipeDistance, keybordDistance: this.flightParam.keybordDistance, narrowCountFactor: this.flightParam.narrowCountFactor, narrorColor: this.flightParam.narrorColor,  stencilRef: this.flightParam.stencilRef}, this.verticalParam, this.flightRange);
        this.leftClickCallback = this.leftClickListener.bind(this);
        this.app.on(Events.Click, this.leftClickCallback, this);
        this.rightClickCallback = this.rightClickListener.bind(this);
        this.app.on(Events.RightClick, this.rightClickCallback, this);
        this.editWaypoinCallback = this.editWaypoinListener.bind(this);
        this.app.on('editWaypoint', this.editWaypoinCallback, this);
    }

    /**
     * 开始操作航线
     * @param operatorMode 1代表编辑，2代表选择
     * @returns 
     */
    public startOperator() {
        if (this.isDisposed) {
            console.warn('The flight is destroyed !');
            return;
        }

        this.isStartOperator = true;
        this.editRoute.startOperator(true);
    }

    /**
     * 关闭操作航线
     */
    public closeOperator(){
         if (this.isDisposed) {
            console.warn('The flight is destroyed !');
            return;
        }

        this.isStartOperator = false;
        this.editRoute.startOperator(false);
        this.editRoute.unSelectClickEvent();
    }

    public dispose() {
        this.app.off(Events.Click, this.leftClickCallback, this);
        this.app.off(Events.RightClick, this.rightClickCallback, this);
        this.app.off('editWaypoint', this.editWaypoinCallback, this);

        this.editRoute.dispose();
        this.isDisposed = true;
    }

    public isInRange(point: Point) {
        let circelCenter = this.flightRange.circelCenter.clone().toEPSGWeb();
        point.z = circelCenter.z;
        point = point.toEPSGWeb();

        let distance = point.distanceTo(circelCenter);
        if (distance > this.flightRange.circleRadius) {
            return false;
        }
        return true;
    }

    private leftClickListener(e) {
        if (this.isStartOperator == false ) { //没有开启航线编辑操作
            return;
        }

        //编辑模式下选中的是航点或航线
        if (e.object['flightPointTag'] == true || e.object['flightRouteTag'] == true) {
            e.object['flightClick'](e);
            return;
        }

        if(this.isDragStatus){ //航点可以拖拽的状态
            this.editRoute.unSelectClickEvent(e);
            this.isDragStatus = false;
            return;
        }

        let point = e.lnglat.clone();

        if (this.flightRange && !this.isInRange(point.clone())) { //航点超出了最大范围
            this.app.fireEvent(Const.FlightRoute.crossRange);
            return;
        }

        if (this.isFirstClick) {
            if (this.flightParam.editMode == 'sameHeight') {
                this.flightParam.initHeight = point.z + this.flightParam.initHeight;
            }
        }

        if (this.flightParam.editMode == 'sameHeight') {
            point.z = this.flightParam.initHeight;
            let topPosition = this.editRoute.getVerticalTopPoint(point.clone().toEPSGWeb());
            if (topPosition && (topPosition.z + this.flightParam.minDistanceFromGround > point.z)) {
                point.z = topPosition.z + this.flightParam.minDistanceFromGround;
            }
        } else {
            point.z += this.flightParam.initHeight;
        }

        this.editRoute.addPoint(point);

        this.isFirstClick = false;
    }

    private rightClickListener(e){
         this.editRoute.unSelectClickEvent(e);
    }

    private editWaypoinListener(isEditWaypoint){
        this.isDragStatus = isEditWaypoint;
    };

    public getFlightPointArray() {
        if (!this.editRoute) {
            return null;
        }
        return this.editRoute.getRoutePointArray();
    }

    public selectWaypoint(index: number) {
        this.editRoute.selectWaypoint(index);
    }

    public removePoint(index: number) {
        this.editRoute.removePoint(index);
    }

    public updatePoint(index: number, newPoint: Point, isNotify: boolean) {
        this.editRoute.updatePoint(index, newPoint, isNotify);
    }

    public checkFlightSafe(): boolean {
        if (!this.editRoute) {
            return false
        }
        return this.editRoute.checkFlightSafe();
    }
}